package com.techysky.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ObjectUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.techysky.entity.Adapt;
import com.techysky.entity.DataModule;
import com.techysky.entity.MaintPlan;
import com.techysky.entity.MediaDm;
import com.techysky.entity.MultiMedia;
import com.techysky.entity.PmDm;
import com.techysky.entity.Project;
import com.techysky.entity.PublicModule;
import com.techysky.repository.AdaptRepository;
import com.techysky.repository.DataModuleRepository;
import com.techysky.repository.MaintPlanRepository;
import com.techysky.repository.MediaDmRepository;
import com.techysky.repository.MultiMediaRepository;
import com.techysky.repository.PmDmRepository;
import com.techysky.repository.ProjectRepository;
import com.techysky.repository.PublicModuleRepository;
import com.techysky.service.XmlService;
import com.techysky.util.HtmlUtils;
import com.techysky.util.IetmUtils;
import com.techysky.util.MainPlanUtils;
import com.techysky.util.UnitUtils;
import com.techysky.xsd.adapt.Assign;
import com.techysky.xsd.adapt.Cond;
import com.techysky.xsd.adapt.Product;
import com.techysky.xsd.adapt.ProductAttribute;
import com.techysky.xsd.dm.AccessPointRef;
import com.techysky.xsd.dm.Dmodule;
import com.techysky.xsd.dm.Limit;
import com.techysky.xsd.dm.MaintPlanning;
import com.techysky.xsd.dm.ProductionMaintData;
import com.techysky.xsd.dm.SupervisorLevel;
import com.techysky.xsd.dm.TaskDefinition;
import com.techysky.xsd.dm.ZoneRef;
import com.techysky.xsd.pm.DmRef;
import com.techysky.xsd.pm.Pm;
import com.techysky.xsd.pm.PmEntry;

/**
 * xml解析实现类
 * @author zhangxu
 *
 */
@Service("xmlService")
public class XmlServiceImpl implements XmlService {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final Logger logger = LoggerFactory.getLogger(XmlServiceImpl.class);
	private static final String GRAPHIC = "graphic";
	private static final String TITLE = "title";
	private static final String INFO_ENTITY_IDENT = "infoEntityIdent";
	@Autowired
	private ApplicationContext ac;
	private int orderCode = 0;
	@Autowired
	private Environment env;
	@Autowired
	private transient UnitUtils unitUtils;
	@Autowired
	private PmDmRepository pmDmRepository;
	@Autowired
	private AdaptRepository fitnessRepository;
	@Autowired
	private ProjectRepository projectRepository;
	@Autowired
	private MediaDmRepository mediaDmRepository;
	@Autowired
	private MaintPlanRepository maintPlanRepository;
	@Autowired
	private MultiMediaRepository multiMediaRepository;
	@Autowired
	private DataModuleRepository dataModuleRepository;
	@Autowired
	private PublicModuleRepository publicModuleRepository;
	

	
	@Override
	public void parse(File folder, String projectId) {
		if(folder.exists()&&folder.isDirectory()) {//首先判断该目录是否存在,
		File[] mediaList = folder.listFiles(file->!file.getName().toLowerCase().contains(".xml")&&file.isFile());
		if(!ObjectUtils.isEmpty(mediaList))parseMedia(mediaList,projectId);//解析多媒体
		File[] dmList = folder.listFiles(file->file.getName().toUpperCase().startsWith("DMC-")&&file.getName().toLowerCase().endsWith(".xml"));
		if(!ObjectUtils.isEmpty(dmList))parseDM(dmList,projectId);//解析DM,该DM包含适用性和维修计划
		File[] pmList = folder.listFiles(file->file.getName().toUpperCase().startsWith("PMC-")&&file.getName().toLowerCase().endsWith(".xml"));
		if(!ObjectUtils.isEmpty(pmList))parsePM(pmList,projectId);//解析PM，由于PM没有编码，因此最后解析，解析出的树形结构每一级的叶子节点挂的都是dm数据页面，根据实际情况，以xml+xsl打开或者生成html页面
		File[] exts = folder.listFiles(file->file.isDirectory());//文件夹复制，暂未放
		}else logger.debug("项目包解压失败");
	}
	
	/**
	 * 1、解析dm数据入库
	 * 2、dm文件生成html页面(可选)
	 * @param files
	 */
	public void parseDM(File[] files,String projectId) {
		Arrays.asList(files).forEach(file->parseDm(file,projectId));//解析入库
		Arrays.asList(files).forEach(file->parseHtml(file));//替换html
	}
	
	/**
	 * 解析多媒体入库
	 * 1、元素对照
	 * 2、数据入库
	 * 3、拷贝文件到指定路径下
	 * @param files
	 * @param projectId
	 */
	public void parseMedia(File[] files,String projectId) {
		Arrays.asList(files).forEach(file->{
			MultiMedia mm = new MultiMedia();
			mm.setCode(file.getName().substring(0, file.getName().indexOf('.')));
			mm.setIcn(mm.getCode());
			mm.setExtName(file.getName().substring(file.getName().indexOf('.')));
			mm.setProjectId(projectId);
			mm.setUrl("/html/"+file.getName());
			this.multiMediaRepository.save(mm);
			try {
				FileCopyUtils.copy(file, new File(env.getProperty("html.path")+file.getName()));
			} catch (IOException e) {
				logger.debug(e.getMessage());
			}
		});
	}
	
	/**
	 * 单个 数据包解析数据
	 * 1、区分不同xsl
	 * 2、数据项对照，url编写
	 * 3、更新多媒体数据，根据多媒体的icn编码进行更新
	 * 4、解析适用性数据
	 * 5、解析维修计划类数据
	 * @param file
	 */
	private void parseDm(File file,String projectId) {
		if(file.getName().contains("00P")||file.getName().contains("00Q")||file.getName().contains("00W")) {
			parseAdapt(file, projectId);
		}else {
			String ietmType = IetmUtils.dmType(file).trim();
			if(env.getProperty("s1000d.schema").contains(ietmType)) {//指定xsl
				Dmodule dmodule=IetmUtils.xml2Bean(file, Dmodule.class);
				String id=dmodule.getContent().getId();
				String code="DMC-"+dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().toString()+"_"+dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getIssueInfo().toString();
				String dmCode=dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().toString();
				String title=dmodule.getIdentAndStatusSection().getDmAddress().getDmAddressItems().getDmTitle().toString();
				String verNo=dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getIssueInfo().getInWork();
				String verType=dmodule.getIdentAndStatusSection().getDmStatus().getIssueType();
				String fitName="all";
				DataModule dm=this.dataModuleRepository.findByDmCode(dmCode);
				if(ObjectUtils.isEmpty(dm)) dm = new DataModule();
					dm.setDmCode(dmCode);
					dm.setCode(code);
					dm.setTitle(title);
					dm.setVerNo(verNo);
					dm.setVerType(verType);
					dm.setFitName(fitName);
					dm.setModelIdentCode(dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().getModelIdentCode());
					dm.setSystemCode(dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().getSystemCode());
					dm.setSubSystemCode(dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().getSubSystemCode());
					dm.setSubSubSystemCode(dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().getSubSubSystemCode());
					dm.setAssyCode(dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().getAssyCode());
					dm.setInfoCode(dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().getInfoCode());
					dm.setPmCode("IETM");
					if(!ObjectUtils.isEmpty(dmodule.getIdentAndStatusSection().getDmStatus().getApplic().getAsserts())&&!ObjectUtils.isEmpty(dmodule.getIdentAndStatusSection().getDmStatus().getApplic().getAsserts().getApplicPropertyValues()))
					fitName=dmodule.getIdentAndStatusSection().getDmStatus().getApplic().getAsserts().getApplicPropertyValues();
					dm.setFitName(fitName);
						//dm.setApplic(dmodule.getIdentAndStatusSection().getDmStatus().getApplic().getAsserts().getApplicPropertyValues());
				if(!ObjectUtils.isEmpty(id)&&!dm.getUrl().contains("/ext/")) {//wrl。u3d和一些无法直接编辑的多媒体实现方式
					dm.setUrl(dm.getUrl().substring(0,dm.getUrl().lastIndexOf('/'))+id);
				}
				//以下是将xml转成html
			/*	String htmlName=xml2html(file, ietmType);
				dm.setUrl("/html/"+htmlName);
				String dmContent=HtmlUtils.replacHtml(env.getProperty("html.path"),htmlName,ac);
				dm.setContent(dmContent);*/
				dm=this.dataModuleRepository.save(dm);
				updateMediaByDm(file,dm);
				//计划类数据需要单独入库
				if(ietmType.equals("schedul")) {
					parseMainPlan(projectId, dmodule, dm);
				}
				
			}
		}
		
	}
	
	private void parseHtml(File file) {
		if(!file.getName().contains("00P")&&!file.getName().contains("00Q")&&!file.getName().contains("00W")) {
			String ietmType = IetmUtils.dmType(file).trim();
			if(env.getProperty("s1000d.schema").contains(ietmType)) {//指定xsl
				Dmodule dmodule=IetmUtils.xml2Bean(file, Dmodule.class);
				String dmCode=dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().toString();
				DataModule dm=this.dataModuleRepository.findByDmCode(dmCode);		
				//以下是将xml转成html
				String htmlName=xml2html(file, ietmType);
				dm.setUrl("/html/"+htmlName);
				String dmContent=HtmlUtils.replacHtml(env.getProperty("html.path"),htmlName,ac);
				dm.setContent(dmContent);
				dm=this.dataModuleRepository.save(dm);
			}
		}
		
	}

	/**
	 * 解析维修计划入库
	 * @param projectId
	 * @param dmodule
	 * @param dm
	 */
	private void parseMainPlan(String projectId, Dmodule dmodule, DataModule dm) {
		MaintPlanning maintplan = dmodule.getContent().getMaintPlanning();
		String maintPlanningType =maintplan.getMaintPlanningType();
		if(maintplan.getTaskDefinition()!=null&&dm!=null){
			List<TaskDefinition> taskdList =maintplan.getTaskDefinition();
			for( int ii=0;ii<taskdList.size();ii++){
				MaintPlan mp = new MaintPlan();
				TaskDefinition taskd = taskdList.get(ii);
				mp.setDmodelId(dm.getId());
				mp.setMaintPlanningType(maintPlanningType);
				mp.setProjectId(projectId);
				mp.setTaskCode(taskd.getTaskIdent());
				mp.setTaskDesc(taskd.getTask().getTaskDescr());
				mp.setRemarks(taskd.getRemarks());
				mp.setDeviName(taskd.getName());
				mp.setApplicRef(taskd.getApplicRefId());
				if(taskd.getRefs()!=null){
					if(taskd.getRefs().getDmRef()!=null){
						taskd.getRefs().getDmRef().forEach(dmRef->{
							if(dmRef.getDmRefIdent()!=null){
								mp.setHrefPath(dmRef.getDmRefIdent().getDmCode().toString());
							}
							if(dmRef.getDmRefAddressItems()!=null&&dmRef.getDmRefAddressItems().getDmTitle()!=null){
								mp.setRefsName(dmRef.getDmRefAddressItems().getDmTitle().toString());
							}	
							
							if (!ObjectUtils.isEmpty( taskd.getPreliminaryRqmts() )&&!ObjectUtils.isEmpty(taskd.getPreliminaryRqmts().getProductionMaintData())) {
								List<ProductionMaintData> pmdList = taskd.getPreliminaryRqmts().getProductionMaintData();
								String area = ""; // 既指区域，也指维护部位名称
								String areaNum = ""; // 维护部位号
								String cap = "";
								if (pmdList != null && !pmdList.isEmpty()) {
									for (int i = 0; i < pmdList.size(); i++) {
										if (i != 0) {
											area += "/";
											areaNum += "/";
											cap += "/";
										}
										ProductionMaintData pmd = pmdList.get(i);
										List<ZoneRef> zrList = pmd.getZoneRef();
										if (!zrList.isEmpty()) {
											area = zrList.stream().map(zr->!ObjectUtils.isEmpty(zr.getName())?zr.getName():"").collect(Collectors.joining("/"));
											areaNum = zrList.stream().map(zr->!ObjectUtils.isEmpty(zr.getZoneNumber())?zr.getZoneNumber():"").collect(Collectors.joining("/"));
										}
										List<AccessPointRef> aprList = pmd.getAccessPointRef();
										if (!aprList.isEmpty()) {
											cap = aprList.stream().map(apr->!ObjectUtils.isEmpty(apr.getName())?apr.getName():"").collect(Collectors.joining("/"));
										}
									}
								}
								mp.setAreaName(area);
								mp.setAreaNumber(areaNum);
								mp.setCapsName(cap);
								
								if (taskd.getLimit() != null) {
									Limit limit = taskd.getLimit();
									if ("pe".equals(limit.getLimitTypeValue().value())) {
										if (limit.getThreshold() != null) {
											// 修改日期：20171020 lingang
											int k = Integer.valueOf(limit.getThreshold().getThresholdValue()) - Integer.valueOf(limit.getThreshold().getThresholdValue()) +limit.getThreshold().getTolerance().getToleranceHigh();
											String unit = limit.getThreshold().getThresholdUnitOfMeasure();
											if (unit != null && unit != "") {
												unit = this.unitUtils.getUnitMap().get(unit);
											}
											mp.setLimitCond(String.valueOf(k) + unit);
										}
									} else if ("oc".equals(limit.getLimitTypeValue().value())) {
										mp.setLimitCond(limit.getLimitCond());
									}
								}
								if (taskd.getSupervisorLevel() != null) {
									SupervisorLevel sl = taskd.getSupervisorLevel();
									if (sl.getSupervisorLevelCode() != null) {
										mp.setLevelCode(MainPlanUtils.getMainPlanLevel(sl.getSupervisorLevelCode().value()));
									}
								}
							}
						});
						maintPlanRepository.save(mp);
					}
				}
		}
		}
	}
	

	/**
	 * xml转html，目前支持 descript ipd fault proced schedul,同时替换文件内容
	 * @param file
	 * @param ietmType
	 * @return
	 */
	private String xml2html(File file, String ietmType) {
		File xslFile=new File(env.getProperty("xsl.path")+ietmType+".xsl");
		String htmlName=IetmUtils.gengeryHtml(file, xslFile, env.getProperty("html.path"));
		return htmlName;
	}
	

	
	/**
	 * 适用性可根据文件名 00P,00Q,00W进行区分，以最后00W为主
	 * @param file
	 * @param projectId
	 */
	private void parseAdapt(File file, String projectId) {
		//此处数据是适用性数据
		com.techysky.xsd.adapt.Dmodule dmodule=IetmUtils.xml2Bean(file, com.techysky.xsd.adapt.Dmodule.class);
		String dmCode=dmodule.getIdentAndStatusSection().getDmAddress().getDmIdent().getDmCode().toString();
		String dmTitle=dmodule.getIdentAndStatusSection().getDmAddress().getDmAddressItems().getDmTitle().toString();
		if(file.getName().contains("00P")) {//有隐患
			List<Product> products=dmodule.getContent().getProductCrossRefTable().getProduct();
			for (Product product : products) {
				Adapt fitness=new Adapt();
				List<Assign> assigns=product.getAssign();
				fitness.setProjectId(projectId);
				fitness.setDmCode(dmCode);
				fitness.setDmTitle(dmTitle);
				String name="";
				for (Assign assign : assigns) {
					name+=assign.getApplicPropertyIdent()+":"+assign.getApplicPropertyValue()+" ";
				}
				fitness.setName(name);
				this.fitnessRepository.save(fitness);
			}
		}else if(file.getName().contains("00Q")) {
			List<Cond> conds=dmodule.getContent().getCondCrossRefTable().getCondList().getCond();
			for (Cond cond : conds) {
				List<Adapt> fitnesses = this.fitnessRepository.findByDmCode(dmCode.replaceAll("00Q", "00P"));
				for (Adapt fitness : fitnesses) {
					fitness.setName(fitness.getName().replace(cond.getId(),cond.getName()));
					this.fitnessRepository.save(fitness);
				}
			}
		}else{
			List<ProductAttribute> attributes=dmodule.getContent().getApplicCrossRefTable().getProductAttributeList().getProductAttribute();
			for (ProductAttribute productAttribute : attributes) {
				List<Adapt> fitnesses = this.fitnessRepository.findByDmCode(dmCode.replaceAll("00W", "00P"));
				for (Adapt fitness : fitnesses) {
					fitness.setName(fitness.getName().replace(productAttribute.getId(), productAttribute.getName()));
					this.fitnessRepository.save(fitness);
				}	
			}
		}
	}
	
	
	
	/**
	 * 通过dm文件更新数据，理论上不会存在多媒体没有入库的现象，该步骤只进行更新
	 * @param file xml文件
	 * @param dm 数据包
	 */
	public void updateMediaByDm(File file,DataModule dm) {
		try( FileInputStream is = new FileInputStream(file)) {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.parse(is);
        NodeList list = document.getElementsByTagName("figure");
        for (int i = 0; i < list.getLength(); ++i){
            Element element = (Element) list.item(i);
            String title = null!=element.getElementsByTagName(TITLE)&&element.getElementsByTagName(TITLE).item(0)!=null?element.getElementsByTagName(TITLE).item(0).getTextContent():"";
            String code = null!=element.getElementsByTagName(GRAPHIC)?element.getElementsByTagName(GRAPHIC).item(0).getAttributes().getNamedItem(INFO_ENTITY_IDENT).getNodeValue():"";
            MultiMedia media=this.multiMediaRepository.findByIcn(code);
            if(!ObjectUtils.isEmpty(media)) {
            	media.setDmCode(dm.getDmCode());// String dmCode = file.getName().substring(0,file.getName().lastIndexOf('.'));
            	media.setTitle(title);
            	this.multiMediaRepository.save(media);
            	MediaDm md = new MediaDm();//有隐患
            	md.setDmId(dm.getId());
            	md.setDmCode(dm.getDmCode());
            	md.setDmTitle(dm.getDmTitle());
            	md.setTitle(title);
            	md.setMediaId(media.getId());
            	md.setIcn(code);
            	this.mediaDmRepository.save(md);
            }else {
            	logger.debug("多媒体文件不存在"+code);	
            }
        }
		} catch (Exception e) {
			logger.debug(e.getMessage());
		}
	}
	
	/**
	 * 解析PM数据包
	 * 标准的数据包只有一个PMC文件
	 * @param files
	 * @param projectId
	 */
	public void parsePM(File[] files,String projectId) {
		if(ObjectUtils.isEmpty(files)||(!ObjectUtils.isEmpty(files)&&files.length>1)) {//如果数据包不存在或者PMC文件数量超过2个说明该数据包有问题
			logger.debug("数据包有问题(不存在PMC文件或者PMC文件不止一个)");
		}else {
			Arrays.asList(files).forEach(file->{
				Pm pm = IetmUtils.xml2Bean(files[0], Pm.class);
				PublicModule publicModule = new PublicModule();//
				publicModule.setCode(pm.getIdentAndStatusSection().getPmAddress().getPmIdent().getPmCode().toString());
				publicModule.setTitle(pm.getIdentAndStatusSection().getPmAddress().getPmAddressItems().getPmTitle());
				publicModule.setParentId("1");
				publicModule=this.publicModuleRepository.save(publicModule);
				//以下是二级或则更深层级的pm结构
				parsePm(pm.getContent().getPmEntry(),projectId,publicModule.getId());
			});
		}
		
		
	}
	
	/**
	 * 解析PM文件分2类，如果是dm就递归结束，否则循环pm
	 * @param pmEntries
	 * @param projectId 项目id，
	 * @param parentId,为了体现层级关系
	 */
	private void parsePm(List<PmEntry> pmEntries,String projectId,String parentId) {
		pmEntries.forEach(pmEntry->{
			PublicModule pm=new PublicModule();
			pm.setTitle(pmEntry.getPmEntryTitle().trim());
			pm.setProjectId(projectId);
			pm.setParentId(parentId);
			pm=this.publicModuleRepository.save(pm);
			//如果pm下有dm
			if(!ObjectUtils.isEmpty(pmEntry.getDmRef())){
				//此处做关联，关联dm和pm
				List<DmRef> refs = pmEntry.getDmRef();
				if(!refs.isEmpty()) {
					for (DmRef dr : refs) {
						DataModule dm = this.dataModuleRepository.findByDmCode(dr.getDmRefIdent().getDmCode().toString());
						if(!ObjectUtils.isEmpty(dm)) {
							PmDm pd = this.pmDmRepository.findByDmIdAndPmId(dm.getId(), pm.getId());
							if(ObjectUtils.isEmpty(pd)) {
								pd = new PmDm();
								pd.setDmId(dm.getId());
								pd.setPmId(pm.getId());
								pd.setDmCode(dr.getDmRefIdent().getDmCode().toString());
								if(!ObjectUtils.isEmpty(dr.getDmRefAddressItems())&&!ObjectUtils.isEmpty(dr.getDmRefAddressItems().getDmTitle()))
								 pd.setDmTitle(dr.getDmRefAddressItems().getDmTitle().toString());
								pd.setOrderCode(orderCode);
								orderCode++;
								this.pmDmRepository.save(pd);
							}
						}
					}	
				}
			}
			if(!ObjectUtils.isEmpty(pmEntry.getPmEntry())) {
				parsePm(pmEntry.getPmEntry(), projectId, pm.getId());
			}
		});
	}

}